/**
 * Created by PengWei on 2018/7/24.
 */

namespace mengdao {
    /**
     * 注入器
     */
    export class Injector {
        /** 实例绑定列表 */
        private _binders: Map<any, Binder<any>>;

        /** 键值对应列表 */
        private _mappers: Map<any, any>;

        /** 上下文 */
        private _context: Context;

        public constructor(context: Context) {
            this._context = context;
            this.init();
        }

        /**
         *  初始化
         */
        private init(): void {
            this._binders = new Map<any, Binder<any>>();
            this._mappers = new Map<any, any>();
        }

        /**
         *  绑定
         */
        public bind<T>(type: TypeIdentifier<T>): Binder<T> {
            if (!this._binders.has(type)) {
                let binder = new Binder(type);
                this._binders.set(type, binder);
                return binder;
            }
            return this._binders.get(type);
        }

        /**
         * 获取绑定实例
         * @param {mengdao.TypeIdentifier<T>} type  绑定Key
         * @param args  构造函数参数 （非必须）
         * @returns {T} 实例
         */
        public getFromBind<T>(type: TypeIdentifier<T>, ...args): T {
            if (this._binders.has(type)) {
                let binder = this._binders.get(type);
                let rawInstance = binder.rawInstance;
                let instance = binder.getInstance(...args);

                if (!rawInstance && instance)
                    this._context.dispatchEventWith(ContextEvent.NEW_INSTANCE_IN_BIND, false, type);

                return instance;
            }
            return null;
        }

        /**
         * 绑定键值对，键任意类型，值一般为binder里注册过或需要注册的定义
         * @param type
         * @param {mengdao.TypeIdentifier<T>} value
         * @returns {boolean}
         */
        public map<T>(type, value: TypeIdentifier<T>, once: boolean = false): void {
            if (!this._mappers.has(type)) {
                this._mappers.set(type, value);
                this._context.dispatchEventWith(ContextEvent.BIND_MAP, false, new ContextEventBindData(type, value, once));
            }
        }

        /**
         * 解绑键值对，但不会对value作任何处理
         * @param type
         */
        public unmap(type: any) {
            if (this._mappers.has(type)) {
                this._mappers.delete(type);
            }
        }

        /**
         * 从绑定的键值对中取值所对应的实例
         * @param type
         * @returns {T}
         */
        public getFromMap(type, ...args): any {
            if (this._mappers.has(type)) {
                let value = this._mappers.get(type);
                return value;
            }
            return null;
        }

        /**
         *  解绑，但不销毁
         *  销毁由被解绑对象自己处理
         */
        public unbind<T>(type: TypeIdentifier<T>) {
            if (this._binders.has(type)) {
                this._binders.delete(type);
            }
        }

        /**
         * 全部解绑，但不销毁
         * 销毁由解绑对象自己处理
         */
        public unbindAll(): void {
            this._binders.clear();
        }
    }
}